package com.siteseat.crudeq.kernel;

import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;

import com.siteseat.common.foundation.Rater;
import com.siteseat.common.misc.SizeUnit;
import com.siteseat.crudeq.common.raw.Constants;

/**
 *
 */
public class ChunkWriter implements Constants {

  private ChunkInfo      info;

  private int            written;

  private FileDescriptor descriptor;

  private OutputStream   stream;

  private Rater          rater;

  /**
   * Ctor only for open()
   * 
   * @param profile
   * @throws IOException
   */
  public ChunkWriter( ChunkInfo info ) throws IOException {
    this.info = info;

    FileOutputStream fos = info.create();
    this.stream = fos;
    this.descriptor = fos.getFD();

    this.written = 0;

    this.rater = new Rater( SizeUnit.MB, TimeUnit.SECONDS, "Save rater:" + this );
  }

  /**
   * @throws IOException
   */
  public void close() throws IOException {
    if( this.stream != null && this.descriptor != null ) {
      this.rater.start();
      try {
        this.stream.flush();
        this.descriptor.sync();
        this.stream.close();
      } finally {
        this.rater.stop();
  
        this.descriptor = null;
        this.stream = null;
      }
    }
  }

  /**
   * @throws IOException
   */
  public void save( Chunk c ) throws IOException {
    assert c.notAllSaved();
    assert c.getInfo() == this.info;

    // assume only the scheduler thread will change the save point
    this.rater.start();
    try {
      int count = c.saveTo( this.info, this.stream );
      this.written += count;
      this.rater.increase( count );

      if( this.info.getProfile().isSyncOnSave() ) {
        this.stream.flush();
        this.descriptor.sync();

        this.info.increaseSize( count );
        assert this.written == this.info.getSize();
      } else {
        this.info.clearSize();
      }
    } finally {
      this.rater.stop();
    }
  }

}
